package com.example.demo.utils;


import org.apache.commons.io.IOUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Description 文件导出
 * @Author chenhuiyu
 */
public class ExcelFileExportUtil {
    public static final String FILE_SUFFIX = ".csv";
    public static final String CSV_DELIMITER = ",";
    public static final String CSV_TAIL = "\r\n";
    protected static final String DATE_FORMAT = "yyyyMMddHHmmssSSS";

    public static void oneClickCreation(String savePath, List dataList) {
        String fileName = savePath + ExcelFileExportUtil.buildFileName(dataList);
        String tableName = ExcelFileExportUtil.buildTableName(dataList);
        String body = ExcelFileExportUtil.buildFileBody(dataList);
        ExcelFileExportUtil.writeFile(fileName, tableName);
        ExcelFileExportUtil.writeFile(fileName, body);
    }

    /**
     * @param savePath
     * @param contextStr
     * @Return void
     * @Author chenhuiyu
     * @Description 字符串转csv文件
     */
    public static void createCsvFile(String savePath, String contextStr) throws IOException {
        File file = new File(savePath);
        // 创建文件
        file.createNewFile();
        // 输出流
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        // 写入输出流
        fileOutputStream.write(contextStr.getBytes("gbk"));
//        fileOutputStream.flush();
        fileOutputStream.close();
    }

    /**
     * @param fileName
     * @param content
     * @Return void
     * @Author chenhuiyu
     * @Description 写入csv文件
     */
    public static void writeFile(String fileName, String content) {
        FileOutputStream fileOutputStream = null;
        OutputStreamWriter writer = null;
        try {
            // 写入文件末尾
            fileOutputStream = new FileOutputStream(fileName, true);
            writer = new OutputStreamWriter(fileOutputStream, "gbk");
            writer.write(content);
            writer.flush();
        } catch (IOException e) {
            System.err.println("写入异常 " + e.getMessage());
            ;
        } finally {
            // 关闭
            if (fileOutputStream != null) {
                IOUtils.closeQuietly(fileOutputStream);
            }
            if (writer != null) {
                IOUtils.closeQuietly(writer);
            }
        }
    }


    public static Workbook writeExcel(List<List<String>> dataList, int startRowNum, int columnCount, int columnWidth) {
        try {
            Workbook workBook = new XSSFWorkbook();
            // 创建sheet
            Sheet sheet = workBook.createSheet("sheet1");
            //设置列宽
            for (int i = 0; i < columnCount; i++) {
                sheet.setColumnWidth(i, columnWidth);
            }
            CellStyle textStyle = workBook.createCellStyle();
            DataFormat format = workBook.createDataFormat();
            textStyle.setDataFormat(format.getFormat("0"));
            textStyle.setWrapText(true);
            // 往Excel中写新数据
            for (int j = 0; j < dataList.size(); j++) {
                // 从第startRowNum行开始
                Row row = sheet.createRow(startRowNum + j);
                // 得到要插入的每一条记录
                for (int k = 0; k < dataList.get(j).size(); k++) {
                    // 在一行内循环
                    Cell first = row.createCell(k);
                    first.setCellStyle(textStyle);
                    first.setCellValue(dataList.get(j).get(k));
                }
            }
            return workBook;
        } catch (Exception e) {
            System.err.println("写入excel异常 " + e.getMessage());
            return null;
        }
    }

    /**
     * @param dataList
     * @Return String
     * @Author chenhuiyu
     * @Description 创建文件名
     */
    public static String buildFileName(List dataList) {
        return dataList.get(0).getClass().getSimpleName() + new SimpleDateFormat(DATE_FORMAT).format(new Date()) + FILE_SUFFIX;
    }

    /**
     * @param dataList
     * @Return String
     * @Author chenhuiyu
     * @Description 标题名
     */
    public static String buildTableName(List dataList) {
//        Map<String, Object> map = toMap(dataList.get(0));
        List<String> list = toList(dataList.get(0));
        StringBuilder tableName = new StringBuilder();
//        for (String key : map.keySet()) {
//            tableName.append(key).append(CSV_DELIMITER);
//        }
        for (String key : list) {
            tableName.append(key).append(CSV_DELIMITER);
        }
        return tableName.append(CSV_TAIL).toString();
    }

    /**
     * @param dataList
     * @Return String
     * @Author chenhuiyu
     * @Description 文件内容
     */
    public static String buildFileBody(List dataList) {
        // 转换为map
        List<Map<String, Object>> mapList = new ArrayList<>();
        List<String> list = toList(dataList.get(0));
        for (Object o : dataList) {
            mapList.add(toMap(o));
        }
        StringBuilder stringBuilder = new StringBuilder();
        for (Map<String, Object> rowMap : mapList) {
//            for (String key : rowMap.keySet()) {
            for (String key : list) {
                Object o = rowMap.get(key);
                if (Objects.nonNull(o)) {
                    stringBuilder.append(o).append(CSV_DELIMITER);
                } else {
                    stringBuilder.append("-").append(CSV_DELIMITER);
                }
            }
            stringBuilder.append(CSV_TAIL);
        }
        return stringBuilder.toString();
    }

    /**
     * @param entity
     * @Return Map<String, Object>
     * @Author chenhuiyu
     * @Description 转换为map
     */
    private static <T> Map<String, Object> toMap(T entity) {
        Class<?> aClass = entity.getClass();
        Field[] fields = aClass.getDeclaredFields();
        Map<String, Object> map = new HashMap<>(fields.length);
        for (Field field : fields) {
            if (!"seralVersionUID".equals(field.getName())) {
                try {
                    String methodName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
                    Method declaredMethod = aClass.getDeclaredMethod(methodName);
                    Object fieldValue = declaredMethod.invoke(entity);
                    map.put(field.getName(), fieldValue);
                } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                    System.err.println("toMap方法异常" + e.getMessage());
                }
            }

        }
        return map;
    }

    private static <T> List<String> toList(T entity) {
        Class<?> aClass = entity.getClass();
        Field[] fields = aClass.getDeclaredFields();
        List<String> list = new ArrayList<>();
        for (Field field : fields) {
            if (!"seralVersionUID".equals(field.getName())) {
                try {
                    String methodName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
                    Method declaredMethod = aClass.getDeclaredMethod(methodName);
                    Object fieldValue = declaredMethod.invoke(entity);
                    list.add(field.getName());
                } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                    System.err.println("toList方法异常" + e.getMessage());
                }
            }
        }
        return list;
    }
}
